#include "stream_parse.h"
#include <stdlib.h>
#include "platformAPI.h"

#define LIST_LEN 6

#define GPRS_A6_TCP_REF "+CIPRCV:"

struct parse_unit
{
    ParseObj *seq;
    volatile uint32_t pos;      /* for ref str pos count*/
    volatile uint32_t count;      /* for res pos count*/
    volatile uint32_t stage;    /* 0: -> start; 1:-> ref matched; 2: -> res buf done*/
    volatile uint8_t process;   /* 0: -> PARSE_ING; 1:-> PARSE_DONE*/
    volatile uint8_t send_process; /*0: -> send action start; 1: at start; 2: cmd start; 3: send done */
};

static struct parse_unit *list[LIST_LEN + 1] = {NULL,NULL,NULL,NULL,NULL,NULL};
static volatile int8_t unit_num = 0;
static volatile int8_t send_flag = 0;
static volatile int8_t send_fd = -1;

static int8_t addOneSeqToList(ParseObj *seq)
{
    struct parse_unit *p = NULL;
    int32_t count;
    int32_t fd;

    for(count = 0; count < LIST_LEN; count++)
    {
	if(list[count] == NULL)
	{
	    break;
	}
    }

    if(count == LIST_LEN)
    {
	return -1;
    }
    else
    {
	fd = count;
    }
    
    p = (struct parse_unit *)malloc(sizeof(struct parse_unit));
    if(p == NULL)
    {
	return -1;
    }

    p->seq = seq;
    p->pos = 0;
    p->stage = 0;
    p->process = PARSE_ING;
    p->send_process = 0;
    p->count = 0;
    list[count] = p;
    unit_num++;

#if 0
    printf("[%s] parse_unit pose [%d]\n",__FUNCTION__,p->pos);
    printf("[%s] parse_unit stage [%d]\n",__FUNCTION__,p->stage);
    printf("[%s] parse_unit process [%d]\n",__FUNCTION__,p->process);
    printf("[%s] parse_unit send_process [%d]\n",__FUNCTION__,p->send_process);
    printf("[%s] fd [%d]\n",__FUNCTION__,count);
    printf("[%s] unit_num [%d]\n",__FUNCTION__,unit_num);
#endif

    return fd;
}

static int8_t waitForParseDone(int32_t fd, uint32_t ms)
{
    uint32_t time_count;
    int8_t ret;

    time_count = (ms > 100)?(ms/100):1;
    while(1)
    {
	if(list[fd]->process == PARSE_DONE)
	{
	    printf("[%s] parse done\n",__FUNCTION__);
	    ret = PARSE_DONE;
	    break;
	}
	systemDelayMs(100);
	time_count--;
	if(time_count == 0)
	{
	    ret = PARSE_OVERTIME;
	    break;
	}
    }
    //printf("[%s] after parse. send_flag [%d]\n",__FUNCTION__,send_flag);
    //printf("[%s] fd [%d], send_fd [%d]\n",__FUNCTION__,fd,send_fd);
    if(fd == send_fd)
    {
	send_flag = 0;
    }
    free(list[fd]);
    list[fd] = NULL;
    printf("[%s] wait done. unit_num [%d] send_flag [%d]\n",__FUNCTION__,unit_num,send_flag);
    return ret;
}

static int8_t parseUnitFromInput(int32_t fd,uint8_t data)
{
    uint8_t count;
    struct parse_obj *obj = list[fd]->seq;
    if(list[fd] == NULL || 
       obj == NULL)
    {
	return PARSE_FAIL;
    }

    if(list[fd]->stage == 0)
    {
	/* check if match the ref*/
	if( *(obj->ref.str + list[fd]->pos) == data)
	{
	    *(obj->res.buf + list[fd]->pos) = data;
	    list[fd]->pos++;
	    if( list[fd]->pos == obj->ref.len)
	    {
		printf("[%s] got ref\n",__FUNCTION__);
		//printf("[%s] obj->res.buf is [%s]\n",__FUNCTION__,obj->res.buf);
		list[fd]->stage++;
	    }
	}
	else
	{
	    //printf("[%s] got wrong code in ref\n",__FUNCTION__);
	    for(count = 0; count < (list[fd]->pos); count++)
	    {
		*(obj->res.buf + count) = 0;
	    }
	    list[fd]->pos = 0;
	}
    }
    else if(list[fd]->pos < obj->res.len)
    {
	//printf("[%s] data [%d] [%c]\n",__FUNCTION__,data,data);
	*(obj->res.buf + list[fd]->pos) = data;
	list[fd]->pos++;
	if(list[fd]->pos == obj->res.len)
	{
	    //printf("[%s] parse done. res.buf [%s]\n",__FUNCTION__,obj->res.buf);
	    //printf("[%s] parse done. ref.str [%s]\n",__FUNCTION__,obj->ref.str);
	    //printf("[%s] parse done. cmd.at [%s]\n",__FUNCTION__,obj->cmd.at);
	    return PARSE_DONE;
	}
    }
    return PARSE_ING;
}


struct tcp_pack
{
    uint8_t buf[1024];
    uint32_t len;
    uint8_t channel;
};

static struct tcp_pack tcp_data;
static uint8_t pack_ready = 0;
static uint8_t pack_tmp[1024] = {0};
static uint8_t pack_state = 0;
static uint8_t pack_count = 0;
static uint8_t pack_channel = 0;
static uint8_t pack_str[5] = {0};
static uint32_t pack_len = 0;


static uint32_t strToUint32(uint8_t *str)
{
    uint8_t count = 0;
    uint32_t data = 0;
    while( *(str + count) != 0)
    {
	data = (data * 10) + (*(str + count) - '0');
	count++;
    }
    return data;
}

static void getTcpReadData(data)
{
    uint8_t buf[] = "+CIPRCV:";
    static uint8_t count = 0;

    if(pack_state == 0)
    {
	/* find buf*/
	if(buf[pack_count] == data)
	{
	    pack_count++;
	    if(pack_count == 8)
	    {
		pack_count = 0;
		pack_state = 1;
	    }
	}
	else
	{
	    pack_count = 0;
	}
    }
    else if(pack_state == 1)
    {
	if(data != ',')
	{
	    pack_channel = data;
	}
	else
	{
	    pack_state = 2;
	}
    }
    else if(pack_state == 2)
    {
	if(data != ',')
	{
	    pack_str[count++] = data;
	}
	else
	{
	    pack_len = strToUint32(pack_str);
	    pack_count = 0;
	    pack_state = 3;
	}
    }
    else if(pack_state == 3)
    {
	if(pack_count < pack_len)
	{
	    pack_tmp[pack_count++] = data;
	}
	else if(pack_ready == 0)
	{
	    printf("[%s] pack_count [%d]\n",__FUNCTION__,pack_count);
	    printf("[%s] pack_len [%d]\n",__FUNCTION__,pack_len);
	    printf("[%s] find one packet of tcp\n",__FUNCTION__);
	    memset(tcp_data.buf,0,1024);
	    for(count = 0; count < pack_len; count++)
	    {
		tcp_data.buf[count] = pack_tmp[count];
	    }
	    tcp_data.len = pack_len;
	    tcp_data.channel = pack_channel;
	    memset(pack_tmp,0,1024);
	    memset(pack_str,0,5);
	    pack_state = 0;
	    pack_count = 0;
	    pack_channel = 0;
	    pack_len = 0;
	    pack_ready = 1;
//	    printf("[%s] tcp data :[%s]\n",__FUNCTION__,tcp_data.buf);
	}
    }
}

int32_t getTcpDataFromStream(uint8_t channel,uint8_t *buf,uint32_t len)
{
    uint32_t count = 0;
    if(pack_ready == 1 &&
       tcp_data.channel == channel)
    {
	len = (tcp_data.len > len)?len:tcp_data.len;
	for(count = 0; count < len; count++)
	{
	    buf[count] = tcp_data.buf[count];
	}
	printf("[%s] read buf :[%s]\n",__FUNCTION__,buf);
	pack_ready = 0;
	return len;
    }
    else
    {
	return -1;
    }
}


int8_t streamParseRuntime(void)
{
    uint8_t i = 0;
    int32_t ret = -1;
    int8_t parse_ret = PARSE_FAIL;
    int8_t data;

    if(unit_num > 0)
    {
	while(1)
	{
	    /*get one data from input buf*/
	    ret = gprsUartRead(&data,1);

	    for(i = 0; i < LIST_LEN; i++)
	    {
		if(list[i] != NULL)
		{
		    if(ret == 1)
		    {
			list[i]->process = parseUnitFromInput(i,data);
			if((list[i]->process) == PARSE_DONE)
			{
			    unit_num--;
			}
		    }
		    /* send something */
		    if(list[i]->seq->cmd.len != 0 &&
		       list[i]->seq->cmd.at != NULL &&
		       send_flag == 0)
		    {
			printf("[%s] send cmd [%s]\n",__FUNCTION__,list[i]->seq->cmd.at);
			send_flag = 1;
			send_fd = i;
			printf("[%s] send_fd is [%d]\n",__FUNCTION__,send_fd);
			gprsUartWrite(list[i]->seq->cmd.at,list[i]->seq->cmd.len);
			list[i]->send_process = 1;

		    }

		    if(list[i]->send_process == 2)
		    {
			printf("[%s] send param [%s]\n",__FUNCTION__,list[i]->seq->cmd.param);
			gprsUartWrite(list[i]->seq->cmd.param,
				      list[i]->seq->cmd.param_len);
			list[i]->send_process = 3;
		    }

		    if(list[i]->send_process = 1 &&
		       data == '>')
		    {
			list[i]->send_process = 2;
		    }/*if(list[i]->send_process = 1 &&*/

		}/*if(list[i] != NULL)*/
	    }/*for(i = 0; i < LIST_LEN; i++)*/
	    
	    if(ret <= 0)
	    {
		return -1;
	    }
	    else if(ret == 1)
	    {
		getTcpReadData(data);
	    }
	}/*while(1)*/
    }/*if(unit_num > 0)*/
}

int8_t parseRefFromStream(ParseObj *obj,uint32_t overtime_ms)
{
    int8_t fd;
    int8_t ret = -1;
    /*register the keyword sequence*/
    printf("[%s] 1. register\n",__FUNCTION__);
    fd = addOneSeqToList(obj);
    if(fd < 0)
    {
	return PARSE_FAIL;
    }
    /* wait for*/
    printf("[%s] 2. wait for\n",__FUNCTION__);
    ret = waitForParseDone(fd,overtime_ms);
    return ret;
}


